package com.ruoyi.flowable.service.impl;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.core.web.page.TableSupport;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.flowable.domain.FlowableDeploy;
import com.ruoyi.flowable.service.FlowServiceFactory;
import com.ruoyi.flowable.service.IFlowableDeployService;
import org.flowable.common.engine.impl.db.SuspensionState;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 流程部署Service业务层处理
 *
 * @author ruoyi
 * @date 2023-12-18
 */
@Service
public class FlowableDeployServiceImpl extends FlowServiceFactory implements IFlowableDeployService
{
    /**
     * 查询流程部署
     *
     * @param definitionId 流程部署主键
     * @return 流程部署
     */
    @Override
    public FlowableDeploy selectFlowableDeployByDefinitionId(String definitionId)
    {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .processDefinitionTenantId(SecurityUtils.getEnterpriseCode())
                .latestVersion()
                .orderByProcessDefinitionKey()
                .asc();
        processDefinitionQuery.deploymentId(definitionId);
        if(processDefinitionQuery.count()==0){
            return new FlowableDeploy();
        }
        FlowableDeploy flowableDeploy = new FlowableDeploy();
        ProcessDefinition result = processDefinitionQuery.singleResult();

        flowableDeploy.setDefinitionId(result.getId());
        flowableDeploy.setDeploymentId(result.getDeploymentId());
        flowableDeploy.setVersion(result.getVersion());
        Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(definitionId).singleResult();
        flowableDeploy.setDeploymentTime(deployment.getDeploymentTime());
        flowableDeploy.setSuspended(result.isSuspended());
        flowableDeploy.setProcessKey(result.getKey());
        flowableDeploy.setProcessName(result.getName());
        flowableDeploy.setCategory(deployment.getCategory());
        return flowableDeploy;
    }

    /**
     * 查询流程部署列表
     *
     * @param flowableDeploy 流程部署
     * @return 流程部署
     */
    @Override
    public List<FlowableDeploy> selectFlowableDeployList(FlowableDeploy flowableDeploy)
    {
        List<FlowableDeploy> retList = null;
        // 流程定义列表数据查询
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .processDefinitionTenantId(SecurityUtils.getEnterpriseCode())
                .latestVersion()
                .orderByProcessDefinitionKey()
                .asc();
        if (StringUtils.isNotBlank(flowableDeploy.getProcessKey())) {
            processDefinitionQuery.processDefinitionKeyLike("%" + flowableDeploy.getProcessKey() + "%");
        }
        if (StringUtils.isNotBlank(flowableDeploy.getProcessName())) {
            processDefinitionQuery.processDefinitionNameLike("%" + flowableDeploy.getProcessName() + "%");
        }
        if (StringUtils.isNotBlank(flowableDeploy.getCategory())) {
            processDefinitionQuery.processDefinitionCategory(flowableDeploy.getCategory());
        }
        if (flowableDeploy.getSuspended()!=null) {
           if(!flowableDeploy.getSuspended()){
                processDefinitionQuery.active();
            } else {
                processDefinitionQuery.suspended();
            }
        }
        long pageTotal = processDefinitionQuery.count();
        if (pageTotal <= 0) {
            return new ArrayList<>();
        }
        PageDomain pageDomain = TableSupport.getPageDomain();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        int offset = pageSize * (pageNum - 1);
        List<ProcessDefinition> definitionList = processDefinitionQuery.listPage(offset, pageSize);

        retList = new ArrayList<>(definitionList.size());
        for (ProcessDefinition processDefinition : definitionList) {
            String deploymentId = processDefinition.getDeploymentId();

            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            FlowableDeploy vo = new FlowableDeploy();
            vo.setDefinitionId(processDefinition.getId());
            vo.setProcessKey(processDefinition.getKey());
            vo.setProcessName(processDefinition.getName());
            vo.setVersion(processDefinition.getVersion());
            vo.setCategory(processDefinition.getCategory());
            vo.setDeploymentId(processDefinition.getDeploymentId());
            vo.setSuspended(processDefinition.isSuspended());
            // 流程部署信息
            vo.setCategory(deployment.getCategory());
            vo.setDeploymentTime(deployment.getDeploymentTime());
            retList.add(vo);
        }
        return retList;
    }


    /**
     * 批量删除流程部署
     *
     * @param definitionIds 需要删除的流程部署主键
     * @return 结果
     */
    @Override
    public int deleteFlowableDeployByDefinitionIds(String[] definitionIds)
    {
        for (String deployId : definitionIds) {
            repositoryService.deleteDeployment(deployId, true);
            //deployFormMapper.delete(new LambdaQueryWrapper<WfDeployForm>().eq(WfDeployForm::getDeployId, deployId));
        }
        return definitionIds.length;
    }

    /**
     * 删除流程部署信息
     *
     * @param definitionId 流程部署主键
     * @return 结果
     */
    @Override
    public int deleteFlowableDeployByDefinitionId(String definitionId)
    {
        repositoryService.deleteDeployment(definitionId, true);
        return 1;
    }

    /**
     * 查询部署的所有历史版本
     * @param processKey
     * @return
     */
    @Override
    public List<FlowableDeploy> queryPublishList(String processKey) {
        // 创建查询条件
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
                .processDefinitionTenantId(SecurityUtils.getEnterpriseCode())
                .processDefinitionKey(processKey)
                .orderByProcessDefinitionVersion()
                .desc();
        long pageTotal = processDefinitionQuery.count();
        if (pageTotal <= 0) {
            return new ArrayList<>();
        }
        // 根据查询条件，查询所有版本
        PageDomain pageDomain = TableSupport.getPageDomain();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        int offset = pageSize * (pageNum - 1);
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery
                .listPage(offset, pageSize);
        List<FlowableDeploy> retList = processDefinitionList.stream().map(item -> {
            FlowableDeploy vo = new FlowableDeploy();
            vo.setDefinitionId(item.getId());
            vo.setProcessKey(item.getKey());
            vo.setProcessName(item.getName());
            vo.setVersion(item.getVersion());
            vo.setCategory(item.getCategory());
            vo.setDeploymentId(item.getDeploymentId());
            vo.setSuspended(item.isSuspended());
            return vo;
        }).collect(Collectors.toList());
        return retList;
    }

    /**
     * 改变部署状态
     *
     * @param definitionId
     * @param stateCode
     */
    @Override
    public void updateState(String definitionId, String stateCode) {
        if (SuspensionState.ACTIVE.toString().equals(stateCode)) {
            // 激活
            repositoryService.activateProcessDefinitionById(definitionId, true, null);
        } else if (SuspensionState.SUSPENDED.toString().equals(stateCode)) {
            // 挂起
            repositoryService.suspendProcessDefinitionById(definitionId, true, null);
        }
    }

    /**
     * 查询流程图
     *
     * @param definitionId
     * @return
     */
    @Override
    public String queryBpmnXmlById(String definitionId) {
        InputStream inputStream = repositoryService.getProcessModel(definitionId);
        try {
            return IoUtil.readUtf8(inputStream);
        } catch (IORuntimeException exception) {
            throw new RuntimeException("加载xml文件异常");
        }
    }

}
